/*
 * edulisp.cpp
 *
 *  Created on: 07.04.2011
 *      Author: xdn
 */

#include <iostream>
#include <stdlib.h>
#include <string>
#include <iomanip>
//Библиотечные инклады

#include "edulisp.hpp"
#include "edulisp_scanner.hpp"
#include "edulisp_language.hpp"
#include "edulisp_nametable.hpp"
#include "edulisp_analyser.hpp"
#include "edulisp_interpreter.hpp"
//Локальные инклады

using namespace std;
//Определения используемых пространств имён

int main(int argc, char* argv[])
{
	NameTable NT_Test;
	int ErrorCode;
	FunctionDescriptor RootFunction;


	{
		string s_test =
				";(defun OUTPUT (from to)"
				"	(print from \" -> \" to \"\\n\"))\n\r"
				"(defun TRANSFER (from to aux N)"
				"	(if (= N 1)"
				"		(OUTPUT from to)"
				"		(progn "
				"			(TRANSFER from aux to (- N 1))"
				"			(OUTPUT from to)"
				"			(TRANSFER aux to from (- N 1)))))"
				";(defun HANOI-TOWERS (height)"
				"	(TRANSFER \"A\" \"B\" \"C\" height))"
				"(HANOI-TOWERS (promt \"Enter height\"))"
		; // end of towers

		cout << "Scanning attempt: \"" << s_test << "\"..." << endl;

		//cin >> s_test;
		ErrorCode = Scan(s_test, RootFunction.GetLexemeList(), NT_Test);
		if (ErrorCode > SEC_OK)
		{
			cout << ((ErrorCode == SEC_ERROR) ? "Syntax error during scan phase."
					: "Internal scanner error.") << endl;
			return EXIT_FAILURE_SCANNER;
		}

		for (NameTable::iterator i = NT_Test.begin(); i != NT_Test.end(); i++)
		{
			if ((*i)->GetFunctionDescriptor())
			{
				cout << "Function \"";
				if ((*i)->GetText())
					cout << *((*i)->GetText());
				else
					cout << "NULL";
				cout << "\" lexeme list:" << endl;

				int LexemeCounter = 0;
				LexemeList& LL = (*i)->GetFunctionDescriptor()->GetLexemeList();
				for (LexemeList::iterator i2 = LL.begin();
						i2 != LL.end(); i2++, LexemeCounter++)
				{
					cout << *i2 << ' ';
					if (LexemeCounter == 40)
					{
						cout << endl;
						LexemeCounter = 0;
					}
				}
				cout << endl;
			}
		}
		cout << "Root function lexeme list:" << endl;
		int LexemeCounter = 0;
		for (LexemeList::iterator i = RootFunction.GetLexemeList().begin();
				i != RootFunction.GetLexemeList().end(); i++, LexemeCounter++)
		{
			cout << *i << ' ';
			if (LexemeCounter == 40)
			{
				cout << endl;
				LexemeCounter = 0;
			}
		}
		cout << endl;

		cout << endl;
		cout << endl;
		cout << "Name table size: " << NT_Test.size() << '.' << endl;
		cout << "Lexeme list size: " << RootFunction.GetLexemeList().size() << '.' << endl << endl;

		cout << "Name table:" << endl;
		cout << left << '|' << setw(6) << "ID" << '|' << setw(15) << "TEXT"
				<< '|' << setw(6) << "OWNER" << '|'
				<< setw(20) << "VALUE" << '|' << setw(10) << "TYPE" << '|'
				<< setw(15) << "LEXEME TYPE" << '|' << endl;
		int i = 1;
		for (NameTable::iterator i2 = NT_Test.begin(); i2 != NT_Test.end();
				i2++, i++)
		{
			cout << '|' << setw(6) << i - 1 << '|' << setw(15)
					<< ((*i2)->GetText() ? *((*i2)->GetText()) : "NULL")
					<< '|' << setw(6) << (*i2)->GetOwner()
					<< '|' << setw(20);
			switch((*i2)->GetDataType())
			{
			case DT_STRING:
				cout << '\"' + *((*i2)->GetString()) + '\"' << '|' << setw(10)
					<< "STRING";
				break;
			case DT_INT:
				cout << *((*i2)->GetInteger()) << '|' << setw(10) << "INTEGER";
				break;
			case DT_DOUBLE:
				cout << *((*i2)->GetFloat()) << '|' << setw(10) << "FLOAT";
				break;
			case DT_NULL:
				cout << "NULL" << '|' << setw(10) << "NULL";
				break;
			case DT_USERFUNCTION:
				cout << ((*i2)->ZeroValue() ? "NULL" : "") << '|' << setw(10)
					<< "USERFUNCTION";
			}
			cout << '|' << setw(15);
			switch((*i2)->GetLexemeType())
			{
			case LT_CONST:
				cout << "CONST";
				break;
			case LT_ID:
				cout << "ID";
				break;
			default:
				cout << "UNKNOWN";
			}
			cout << "";
			cout << '|' << endl;
		}

		/*ErrorCode = Analyse(RootFunction.GetLexemeList(), NT_Test);
		if (ErrorCode)
		{
			cout << "Error during analyse phase. Code E" << ErrorCode << ".\n";
			//return EXIT_FAILURE_ANALYSER;
		} else cout << "No analyser errors for you. Sorry." << endl;*/

		Interpreter Int_Test(std::cin, std::cout);
		NameTable_Entry *Result;
		/*ErrorCode = Int_Test.Execute(NT_Test, RootFunction, NULL, Result);
		if (ErrorCode)
		{
			cout << "Interpreter error. Code E" << ErrorCode << '.' << endl;
			return EXIT_FAILURE_INTERPRETER;
		}

		if (Result)
			cout << "Result: " << *Result << endl;*/
	}

	return EXIT_SUCCESS;
}
